home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrscript.win / feature files / vrmovies.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  35.5 KB  |  1,213 lines

  1. //////////
  2. //
  3. //    File:        VRMovies.c
  4. //
  5. //    Contains:    Support for QuickTime movie playback in VR nodes.
  6. //
  7. //    Written by:    Tim Monroe
  8. //                Some code borrowed from QTVRSamplePlayer by Bryce Wolfson.
  9. //
  10. //    Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <25>         04/07/99    rtm        revised VRMoov_StartMovie
  15. //       <24>         03/29/99    rtm        added VRMoov_Init and VRMoov_Stop; conditionalized out the support for
  16. //                                    on-the-fly movie rotation (too many problems reported)
  17. //       <23>         03/29/99    rtm        added VRMoov_StartMovie as a wrapper for StartMovie to handle streamed
  18. //                                    movies; changed StartMovie to VRMoov_StartMovie passim
  19. //       <22>         01/26/99    rtm        changed two occurrences of gw->portPixMap to GetGWorldPixMap(gw)
  20. //       <21>        12/03/98    rtm        modified VRMoov_LoadEmbeddedMovie to accept a string as a parameter,
  21. //                                    which can now be a full URL or a pathname
  22. //       <20>        09/28/98    rtm        added call to DisposeMovie in VRMoov_PlayTransitionMovie to plug leak
  23. //       <19>        09/11/98    rtm        added code to use DecompressImage instead of CopyBits when copying
  24. //                                    an embedded movie frame into the backbuffer; set the compiler flag
  25. //                                    USE_COPYBITS_TO_BACKBUFFER in VRMovies.h to select the desired call
  26. //       <18>        05/04/98    rtm        added support for on-the-fly movie rotation
  27. //       <17>        05/01/98    rtm        added VRMoov_DoIdle call to VRMoov_PlayTransitionMovie, to service
  28. //                                    scene-wide sounds while a transition movie is playing; also added
  29. //                                    call to FlushEvents and cleaned up surrounding code
  30. //       <16>        10/29/97    rtm        modified VRMoov_SetVideoGraphicsMode to use GetMovieIndTrackType
  31. //       <15>         09/18/97    rtm        added parameter to VRMoov_CheckForCompletedMovies
  32. //       <14>         06/24/97    rtm        modified VRMoov_DoIdle to service QuickTime movies with video tracks 
  33. //                                    in non-frontmost windows
  34. //       <13>         06/19/97    rtm        added support for scene-wide sound-only movies
  35. //       <12>         05/13/97    rtm        added VRMoov_PlayTransitionMovie
  36. //       <11>         04/28/97    rtm        reworked to support sound-only movie files as well
  37. //       <10>         04/28/97    rtm        added VRMoov_PlayMovie; reworked passim to use linked list
  38. //       <9>         03/17/97    rtm        added VRMoov_SetMovieBalanceAndVolume
  39. //       <8>         03/12/97    rtm        copied file from VRMovies project and integrated with VRScript
  40. //       <7>         03/06/97    rtm        started to implement video masking
  41. //       <6>         03/05/97    rtm        added VRMoov_SetChromaColor; added fChromaColor to app data record
  42. //       <5>         03/04/97    rtm        fixed compositing problems at back buffer edges
  43. //       <4>         03/03/97    rtm        added VRMoov_SetVideoGraphicsMode to handle compositing
  44. //                                    without using an offscreen GWorld
  45. //       <3>         02/27/97    rtm        further development: borrowed some ideas from QTVRSamplePlayer;
  46. //                                    added VRMoov_SetEmbeddedMovieWidth etc.
  47. //       <2>         12/12/96    rtm        further development: borrowed some ideas from BoxMoov demo 
  48. //       <1>         12/11/96    rtm        first file 
  49. //       
  50. // This code supports playing QuickTime movies in QTVR panoramas. For movies with video tracks,
  51. // this code draws the QuickTime movie frames into the back buffer, either directly or indirectly
  52. // (via an offscreen GWorld). Direct drawing gives the best performance, but indirect drawing is
  53. // necessary for some visual effects. 
  54. //
  55. //////////
  56.  
  57. // TO DO:
  58. // + finish video masking by custom 'hide' hot spots (so video goes *behind* such hot spots)
  59. // + fix: when compositing (either w or w/o offscreen buffer) and movie is not initially visible
  60. //   and movie rect intersects bb rect edge:
  61. //     panning to movie shows some junk in movie rect when movie first visible.
  62. // + fix: when compositing w/o offscreen buffer, there's a blanking at repeat of movie
  63.  
  64. #pragma once
  65.  
  66. // header files
  67. #include <stdlib.h>
  68. #include <QDOffscreen.h>
  69.  
  70. #include "QTUtilities.h"
  71. #include "QTVRUtilities.h"
  72. #include "VRMovies.h"
  73. #include "VRScript.h"
  74.  
  75. // constants
  76. const RGBColor                    kWhiteColor = {0xffff, 0xffff, 0xffff};        // white
  77.  
  78. // global variables
  79. MoviePrePrerollCompleteUPP        gMoviePPRollCompleteProc = NULL;            // a routine descriptor for our sound callback
  80.  
  81.  
  82. //////////
  83. //
  84. // VRMoov_Init
  85. // Initialize for QuickTime movie playback.
  86. //
  87. //////////
  88.  
  89. void VRMoov_Init (void)
  90. {
  91.     // allocate a routine descriptor for our pre-preroll completion routine
  92.     if (gMoviePPRollCompleteProc == NULL)
  93.         gMoviePPRollCompleteProc = NewMoviePrePrerollCompleteProc(VRScript_MoviePrePrerollCompleteProc);
  94. }
  95.  
  96.  
  97. //////////
  98. //
  99. // VRMoov_Stop
  100. // Close down for QuickTime movie playback.
  101. //
  102. //////////
  103.  
  104. void VRMoov_Stop (void)
  105. {
  106.     // deallocate routine descriptor
  107.     if (gMoviePPRollCompleteProc != NULL)
  108.         DisposeRoutineDescriptor(gMoviePPRollCompleteProc);
  109. }
  110.  
  111.  
  112. //////////
  113. //
  114. // VRMoov_StartMovie
  115. // Start a QuickTime movie playing.
  116. //
  117. // This is essentially just a wrapper for StartMovie, to handle preprerolling of streamed movies.
  118. //
  119. //////////
  120.  
  121. void VRMoov_StartMovie (Movie theMovie)
  122. {    
  123.     PrePrerollMovie(theMovie, 0, GetMoviePreferredRate(theMovie), gMoviePPRollCompleteProc, (void *)0L);
  124.     StartMovie(theMovie);
  125. }
  126.  
  127.  
  128. //////////
  129. //
  130. // VRMoov_PlayMovie
  131. // Start a QuickTime movie playing or stop one from playing.
  132. //
  133. //////////
  134.  
  135. void VRMoov_PlayMovie (
  136.                 WindowObject theWindowObject,
  137.                 UInt32 theNodeID,
  138.                 UInt32 theEntryID, 
  139.                 float thePanAngle,
  140.                 float theTiltAngle,
  141.                 float theScale, 
  142.                 float theWidth, 
  143.                 UInt32 theKeyRed, 
  144.                 UInt32 theKeyGreen, 
  145.                 UInt32 theKeyBlue, 
  146.                 Boolean theUseBuffer,
  147.                 Boolean theUseCenter,
  148.                 Boolean theUseKey,
  149.                 Boolean theUseHide,
  150.                 Boolean theUseDir,
  151.                 Boolean theRotate,
  152.                 float theVolAngle,
  153.                 UInt32 theMode,
  154.                 UInt32 theOptions,
  155.                 char *thePathName)
  156. {
  157.     ApplicationDataHdl        myAppData;
  158.     Boolean                    myNeedPlayMovie = false;
  159.     Boolean                    myNeedLoadMovie = false;
  160.     VRScriptMoviePtr        myPointer = NULL;
  161.     
  162.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  163.     if (myAppData == NULL)
  164.         return;
  165.     
  166.     // see if this movie is already in our list of playing movies                
  167.     myPointer = (VRScriptMoviePtr)VRScript_GetObjectByEntryID(theWindowObject, kVREntry_QTMovie, theEntryID);
  168.         
  169.     if (myPointer == NULL) {
  170.         // this movie isn't in our list yet, so we'll need to add it to the list
  171.         myNeedLoadMovie = true;
  172.         myNeedPlayMovie = true;
  173.     } else {
  174.         // this movie is already in our list; theOptions determines how we handle this request:
  175.         
  176.         switch (theOptions) {
  177.         
  178.             case kVRMedia_PlayNew:
  179.                 // start the movie playing (whether it's already playing or not);
  180.                 // multiple movies aren't supported in QTVR 2.0, so we just map to kVRMedia_Continue
  181.                 myNeedPlayMovie = true;
  182.                 myNeedLoadMovie = true;
  183.                 break;
  184.                 
  185.             case kVRMedia_Restart:
  186.                 // stop the current movie and then restart it; use the existing movie data
  187.                 StopMovie(myPointer->fMovie);
  188.                 myNeedPlayMovie = true;
  189.                 myNeedLoadMovie = false;
  190.                 break;
  191.                 
  192.             case kVRMedia_ToggleStop:
  193.                 // toggle the movie's current play/stop state
  194.                 myNeedLoadMovie = false;
  195.                 if (!IsMovieDone(myPointer->fMovie)) {
  196.                     // stop the movie and get rid of movie list entry
  197.                     StopMovie(myPointer->fMovie);
  198.                     VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  199.                     myNeedPlayMovie = false;
  200.                 } else {
  201.                     // start the movie; use the existing movie data
  202.                     myNeedPlayMovie = true;
  203.                 }
  204.                 break;
  205.                 
  206.             case kVRMedia_TogglePause:
  207.                 // toggle the movie's current play/pause state
  208.                 myNeedLoadMovie = false;
  209.                 if (GetMovieRate(myPointer->fMovie) != (Fixed)0) {
  210.                     // stop the movie
  211.                     StopMovie(myPointer->fMovie);
  212.                     myNeedPlayMovie = false;
  213.                 } else {
  214.                     // restart the movie; use the existing movie data
  215.                     myNeedPlayMovie = false;
  216.                     StartMovie(myPointer->fMovie);
  217.                 }
  218.                 break;
  219.                 
  220.             case kVRMedia_Continue:
  221.                 // just let the movie already in progress continue
  222.                 myNeedPlayMovie = false;
  223.                 myNeedLoadMovie = false;
  224.                 break;
  225.                 
  226.             case kVRMedia_Stop:
  227.                 // stop the current movie
  228.                 StopMovie(myPointer->fMovie);
  229.                 myNeedPlayMovie = false;
  230.                 myNeedLoadMovie = false;
  231.                 break;
  232.                 
  233.             default:
  234.                 // unrecognized option
  235.                 // start the movie playing
  236.                 myNeedPlayMovie = true;
  237.                 myNeedLoadMovie = false;
  238.                 break;
  239.         }
  240.     }
  241.     
  242.     if (myNeedLoadMovie) {
  243.         myPointer = VRScript_EnlistMovie (
  244.                         theWindowObject,
  245.                         theNodeID, 
  246.                         theEntryID,
  247.                         thePanAngle,
  248.                         theTiltAngle,
  249.                         theScale, 
  250.                         theWidth, 
  251.                         theKeyRed, 
  252.                         theKeyGreen, 
  253.                         theKeyBlue, 
  254.                         theUseBuffer,
  255.                         theUseCenter,
  256.                         theUseKey,
  257.                         theUseHide,
  258.                         theUseDir,
  259.                         theRotate,
  260.                         theVolAngle,
  261.                         theMode,
  262.                         theOptions,
  263.                         thePathName);
  264.     }
  265.  
  266.     if (myNeedPlayMovie)
  267.         if (myPointer != NULL)
  268.             VRMoov_LoadEmbeddedMovie(thePathName, theWindowObject, myPointer);
  269. }
  270.  
  271.  
  272. //////////
  273. //
  274. // VRMoov_PlayTransitionMovie
  275. // Play a QuickTime movie as a transition from one node to another.
  276. //
  277. //////////
  278.  
  279. void VRMoov_PlayTransitionMovie (WindowObject theWindowObject, UInt32 theOptions, char *thePathName)
  280. {
  281.     FSSpec        myFSSpec;
  282.     short        myMovieFileRef = 0;
  283.     Movie        myMovie;
  284.     Rect        myRect;
  285.     GWorldPtr    myGWorld;
  286.     GDHandle    myGDevice;
  287.     long        myCount = 0;
  288.     Boolean        myUserCancelled = false;
  289.     OSErr        myErr = noErr;
  290.     
  291.     if ((theWindowObject == NULL) || (thePathName == NULL))
  292.         goto bail;
  293.         
  294.     FSMakeFSSpec(0, 0L, c2pstr(thePathName), &myFSSpec);
  295.     
  296.     // open the movie
  297.     myErr = OpenMovieFile(&myFSSpec, &myMovieFileRef, fsRdPerm);
  298.     if (myErr != noErr)
  299.         goto bail;
  300.  
  301.     myErr = NewMovieFromFile(&myMovie, myMovieFileRef, NULL, NULL, newMovieActive, NULL);
  302.     if ((myErr != noErr) || (myMovie == NULL))
  303.         goto bail;
  304.  
  305.     // set the movie GWorld
  306.     GetMovieGWorld((**theWindowObject).fMovie, &myGWorld, &myGDevice);
  307.     SetMovieGWorld(myMovie, myGWorld, myGDevice);
  308.             
  309.     // set the movie box to the size of the QTVR window            
  310.     GetMovieBox((**theWindowObject).fMovie, &myRect);    
  311.     SetMovieBox(myMovie, &myRect);
  312.     
  313.     // start the movie
  314.     GoToBeginningOfMovie(myMovie);
  315.     VRMoov_StartMovie(myMovie);
  316.     
  317.     // play the movie once thru
  318.     while (!IsMovieDone(myMovie) && !myUserCancelled) {
  319.         MoviesTask(myMovie, 0);
  320.         SystemTask();
  321.         
  322.         // on very long transition movies (or very slow machines), scene-wide sound-only movies need to be serviced
  323.         // (but not every time thru the loop, eh?)
  324.         if (myCount % kDoIdleStep == 0)
  325.             VRMoov_DoIdle(theWindowObject);
  326.             
  327.         myCount++;
  328.         
  329.         // see if the user has cancelled the transition movie, if so allowed
  330.         if (theOptions == kVRMovie_PlayTilClick)
  331.             myUserCancelled = Button();
  332.     }
  333.     
  334.     StopMovie(myMovie);
  335.     DisposeMovie(myMovie);
  336.     
  337.     // button clicks during a transition movie remain in the OS event queue (even if detected by the
  338.     // Button call above); we'd better remove them (by calling FlushEvents) or they may trigger a hot
  339.     // spot in the destination node; note that if theOptions is kVRMovie_PlayTilClick, then the first
  340.     // click stops the movie and gets flushed, but any subsequent clicks remain in the OS event queue
  341.     // and get processed normally....
  342.     FlushEvents(mDownMask + mUpMask, 0);
  343.     
  344. bail:
  345.     if (myMovieFileRef != 0)
  346.         CloseMovieFile(myMovieFileRef);
  347. }
  348.  
  349.  
  350. //////////
  351. //
  352. // VRMoov_LoadEmbeddedMovie
  353. // Load the QuickTime movie in the specified file.
  354. // Returns a Boolean to indicate success (true) or failure (false).
  355. //
  356. //////////
  357.  
  358. Boolean VRMoov_LoadEmbeddedMovie (char *thePathName, WindowObject theWindowObject, VRScriptMoviePtr theEntry)
  359. {
  360.     FSSpec                    myFSSpec;
  361.     short                    myMovieFileRef;
  362.     Movie                    myMovie;
  363.     QTVRInstance            myInstance = NULL;
  364.     GWorldPtr                myGWorld = NULL;
  365.     CGrafPtr                mySavedPort;
  366.     GDHandle                mySavedGDevice;
  367.     Rect                    myRect;
  368.     ApplicationDataHdl        myAppData;
  369.     OSErr                    myErr = noErr;
  370.  
  371.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  372.     if (myAppData == NULL)
  373.         return(false);
  374.         
  375.     if (theEntry == NULL)
  376.         return(false);
  377.         
  378.     if (URLUtils_IsAbsoluteURL(thePathName)) {
  379.         // we were passed a URL
  380.         myMovie = URLUtils_NewMovieFromURL(thePathName, newMovieActive, NULL);
  381.     } else {
  382.         // we were passed a filename; create an FSSpec for the file
  383.         FSMakeFSSpec(0, 0L, c2pstr(thePathName), &myFSSpec);
  384.         
  385.         // open the movie
  386.         myErr = OpenMovieFile(&myFSSpec, &myMovieFileRef, fsRdPerm);
  387.         if (myErr != noErr)
  388.             return(false);
  389.  
  390.         myErr = NewMovieFromFile(&myMovie, myMovieFileRef, NULL, (StringPtr)NULL, newMovieActive, NULL);
  391.         if ((myErr != noErr) || (myMovie == NULL))
  392.             return(false);
  393.  
  394.         if (myMovieFileRef != 0)
  395.             CloseMovieFile(myMovieFileRef);
  396.     }
  397.  
  398.     GetMovieBox(myMovie, &myRect);
  399.     MacOffsetRect(&myRect, -myRect.left, -myRect.top);
  400.     SetMovieBox(myMovie, &myRect);
  401.  
  402.     // keep track of the movie and movie rectangle
  403.     theEntry->fMovie = myMovie;
  404.     theEntry->fMovieRect = myRect;
  405.     
  406.     // determine what kinds of media are in this movie
  407.     theEntry->fQTMovieHasSound = QTUtils_IsMediaTypeInMovie(myMovie, SoundMediaType) || QTUtils_IsMediaTypeInMovie(myMovie, MusicMediaType);
  408.     theEntry->fQTMovieHasVideo = QTUtils_IsMediaTypeInMovie(myMovie, VideoMediaType);
  409.     if (theEntry->fQTMovieHasSound)
  410.         theEntry->fMediaHandler = QTUtils_GetSoundMediaHandler(myMovie);
  411.  
  412.     // get rid of any existing offscreen graphics world
  413.     if (theEntry->fMovieGWorld != NULL) {
  414.         UnlockPixels(theEntry->fMoviePixMap);
  415.         DisposeGWorld(theEntry->fMovieGWorld);
  416.     }
  417.  
  418.     if (theEntry->fQTMovieHasVideo) {
  419.         // get current port and GDevice
  420.         GetGWorld(&mySavedPort, &mySavedGDevice);
  421.         
  422.         // clear out any existing custom cover function and reset the video media graphics mode
  423.         // (these may have been modified for direct-screen drawing)
  424.         SetMovieCoverProcs(myMovie, NULL, NULL, 0);
  425.         VRMoov_SetVideoGraphicsMode(myMovie, theEntry, false);
  426.         
  427.         // if necessary, create an offscreen graphics world;
  428.         // this is where we'll image the movie before copying it into the back buffer
  429.         // (which allows us to do special effects)
  430.         if (theEntry->fUseMovieGWorld) {
  431.             myErr = NewGWorld(&myGWorld, 0, &myRect, NULL, NULL, 0L);
  432.             if (myGWorld != NULL) 
  433.                 SetMovieGWorld(myMovie, myGWorld, GetGWorldDevice(myGWorld));
  434.             theEntry->fMovieGWorld = myGWorld;
  435.             theEntry->fMoviePixMap = GetGWorldPixMap(myGWorld);
  436.             LockPixels(theEntry->fMoviePixMap);
  437.         } else {            
  438.             GetMovieGWorld((**theWindowObject).fMovie, &myGWorld, NULL);
  439.             // set the video media graphics mode to drop out the chroma key color in a movie;
  440.             // we also need to install an uncover function that doesn't erase the uncovered region
  441.             if (theEntry->fCompositeMovie) {
  442.                 SetMovieCoverProcs(myMovie, NewMovieRgnCoverProc(VRMoov_CoverProc), NULL, (long)theWindowObject);
  443.                 VRMoov_SetVideoGraphicsMode(myMovie, theEntry, true);
  444.             }
  445.         }
  446.         
  447. #if ALLOW_REALTIME_ROTATION
  448.         // if the script command line requests real-time rotation, set up the rotation matrix
  449.         if (theEntry->fDoRotateMovie) {
  450.             SetIdentityMatrix(&(**myAppData).fRotationMatrix);
  451.             RotateMatrix(&(**myAppData).fRotationMatrix, FixDiv(-90.0, 1), 0, 0);
  452.             SetMovieMatrix(myMovie, &(**myAppData).fRotationMatrix);
  453.         }
  454.         (**myAppData).fDrewPrevBBProc = false;
  455. #endif
  456.         
  457.         // install a back-buffer imaging procedure
  458.         myInstance = (**theWindowObject).fInstance;
  459.         if (myInstance != NULL)
  460.             VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  461.     }
  462.     
  463.     // set initial balance and volume
  464.     if (theEntry->fQTMovieHasSound) {
  465.         VRMoov_SetOneBalanceAndVolume(myMovie, theEntry->fMediaHandler, QTVRGetPanAngle(myInstance), QTVRGetTiltAngle(myInstance), theEntry->fMovieCenter.x, theEntry->fVolAngle);
  466.         (**myAppData).fSoundHasChanged = true;
  467.     }
  468.         
  469.     if (theEntry->fMode == kVRPlay_Loop) {
  470.         // start the movie playing in a loop
  471.         if (theEntry->fQTMovieHasVideo)
  472.             SetMovieGWorld(myMovie, myGWorld, GetGWorldDevice(myGWorld));
  473.         VRMoov_LoopEmbeddedMovie(myMovie);
  474.     } else if (theEntry->fMode == kVRPlay_Once) {
  475.         // play the movie once thru
  476.         GoToBeginningOfMovie(myMovie);
  477.         VRMoov_StartMovie(myMovie);
  478.     }
  479.     
  480.     return(true);
  481. }
  482.     
  483.     
  484. //////////
  485. //
  486. // VRMoov_LoopEmbeddedMovie
  487. // Start the QuickTime movie playing in a loop.
  488. //
  489. //////////
  490.  
  491. void VRMoov_LoopEmbeddedMovie (Movie theMovie)
  492. {
  493.     TimeBase        myTimeBase;
  494.  
  495.     // throw the movie into loop mode
  496.     myTimeBase = GetMovieTimeBase(theMovie);
  497.     SetTimeBaseFlags(myTimeBase, GetTimeBaseFlags(myTimeBase) | loopTimeBase);
  498.  
  499.     // start playing the movie
  500.     VRMoov_StartMovie(theMovie);
  501. }
  502.     
  503.  
  504. //////////
  505. //
  506. // VRMoov_DoIdle
  507. // Do any movie-related processing that can or should occur at idle time.
  508. // Returns true if the caller should call QTVRUpdate, false otherwise.
  509. //
  510. //////////
  511.  
  512. Boolean VRMoov_DoIdle (WindowObject theWindowObject)
  513. {
  514.     ApplicationDataHdl        myAppData;
  515.     VRScriptMoviePtr        myPointer;
  516.     Boolean                    myNeedUpdate = false;
  517.  
  518.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  519.     if (myAppData == NULL)
  520.         return(myNeedUpdate);
  521.     
  522.     // walk the linked list and service any embedded sound-only movies
  523.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  524.     while (myPointer != NULL) {
  525.         if (myPointer->fQTMovieHasSound && !(myPointer->fQTMovieHasVideo)) {
  526.             MoviesTask(myPointer->fMovie, 0L);
  527.         }
  528.         myPointer = myPointer->fNextEntry;
  529.     }
  530.     
  531.     // now service the (single) embedded video movie, if there is one    
  532.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  533.     if (myPointer != NULL) {
  534.         // trip the back buffer procedure, which internally calls MoviesTask;
  535.         // note that this is necessary *only* if the window containing the embedded movie
  536.         // isn't the frontmost window
  537.         if ((**theWindowObject).fWindow != GetFrontMovieWindow())
  538.             myNeedUpdate = true;
  539.     }
  540.     
  541.     return(myNeedUpdate);
  542. }
  543.         
  544.                 
  545. //////////
  546. //
  547. // VRMoov_DumpNodeMovies
  548. // Stop playing all movies enlisted for the current node.
  549. //
  550. //////////
  551.  
  552. void VRMoov_DumpNodeMovies (WindowObject theWindowObject)
  553. {
  554.     VRMoov_DumpSelectedMovies(theWindowObject, kVRSelect_Node);
  555. }
  556.  
  557.  
  558. //////////
  559. //
  560. // VRMoov_DumpSceneMovies
  561. // Stop playing all movies enlisted for the current scene.
  562. //
  563. //////////
  564.  
  565. void VRMoov_DumpSceneMovies (WindowObject theWindowObject)
  566. {
  567.     VRMoov_DumpSelectedMovies(theWindowObject, kVRSelect_Scene);
  568. }
  569.  
  570.  
  571. //////////
  572. //
  573. // VRMoov_DumpSelectedMovies
  574. // Stop any existing embedded movies from playing and then clean up.
  575. //
  576. //////////
  577.  
  578. void VRMoov_DumpSelectedMovies (WindowObject theWindowObject, UInt32 theOptions)
  579. {
  580.     ApplicationDataHdl        myAppData;
  581.     VRScriptMoviePtr        myPointer;
  582.     VRScriptMoviePtr        myNext;
  583.  
  584.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  585.     if (myAppData == NULL)
  586.         return;
  587.  
  588.     // walk the movie list and dump any movies movies associated with this node
  589.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  590.     while (myPointer != NULL) {
  591.         
  592.         myNext = myPointer->fNextEntry;
  593.         if (((myPointer->fNodeID != kVRAnyNode) && (theOptions == kVRSelect_Node)) ||
  594.             ((myPointer->fNodeID == kVRAnyNode) && (theOptions == kVRSelect_Scene)))
  595.             VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  596.         
  597.         myPointer = myNext;
  598.     }
  599.     
  600.     // clear the existing back buffer imaging proc
  601.     VRScript_RemoveBackBufferImagingProc((**theWindowObject).fInstance, theWindowObject);
  602.  
  603.     // make sure the back buffer is clean
  604.     QTVRRefreshBackBuffer((**theWindowObject).fInstance, 0);
  605.  
  606.     return;
  607. }
  608.     
  609.  
  610. //////////
  611. //
  612. // VRMoov_GetEmbeddedVideo
  613. // Return the first embedded QuickTime movie that has a video track.
  614. //
  615. //////////
  616.  
  617. VRScriptMoviePtr VRMoov_GetEmbeddedVideo (WindowObject theWindowObject)
  618. {
  619.     ApplicationDataHdl        myAppData;
  620.     VRScriptMoviePtr        myPointer = NULL;
  621.     
  622.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  623.     if (myAppData == NULL)
  624.         return(myPointer);
  625.         
  626.     // walk our linked list of movies to find the target movie
  627.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  628.     while (myPointer != NULL) {
  629.         if (myPointer->fQTMovieHasVideo)
  630.             return(myPointer);
  631.         myPointer = myPointer->fNextEntry;
  632.     }
  633.     
  634.     return(NULL);
  635. }
  636.  
  637.  
  638. //////////
  639. //
  640. // VRMoov_GetEmbeddedMovieWidth
  641. // Get the width of the embedded movie.
  642. //
  643. //////////
  644.  
  645. float VRMoov_GetEmbeddedMovieWidth (WindowObject theWindowObject)
  646. {
  647.     float                    myWidth = 0.0;
  648.     VRScriptMoviePtr        myPointer;
  649.     
  650.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  651.     if (myPointer != NULL)
  652.         myWidth = myPointer->fMovieWidth;
  653.             
  654.     return(myWidth);
  655. }
  656.  
  657.  
  658. //////////
  659. //
  660. // VRMoov_SetEmbeddedMovieWidth
  661. // Set the width of the embedded movie.
  662. //
  663. //////////
  664.  
  665. void VRMoov_SetEmbeddedMovieWidth (WindowObject theWindowObject, float theWidth)
  666. {
  667.     QTVRInstance            myInstance;
  668.     VRScriptMoviePtr        myPointer;
  669.     
  670.     if (theWindowObject == NULL)
  671.         return;
  672.         
  673.     myInstance = (**theWindowObject).fInstance;
  674.     if (myInstance == NULL)
  675.         return;
  676.     
  677.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  678.     if (myPointer != NULL)
  679.         myPointer->fMovieWidth = theWidth;
  680.  
  681.     // clear out the existing area of interest
  682.     QTVRRefreshBackBuffer(myInstance, 0);
  683.  
  684.     // reinstall the back buffer imaging procedure
  685.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  686. }
  687.  
  688.  
  689. //////////
  690. //
  691. // VRMoov_GetEmbeddedMovieCenter
  692. // Get the center of the embedded movie.
  693. //
  694. //////////
  695.  
  696. void VRMoov_GetEmbeddedMovieCenter (WindowObject theWindowObject, QTVRFloatPoint *theCenter)
  697. {
  698.     VRScriptMoviePtr        myPointer;
  699.     
  700.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  701.     if (myPointer == NULL) {
  702.         theCenter->x = 0.0;
  703.         theCenter->y = 0.0;
  704.     } else {
  705.         theCenter->x = myPointer->fMovieCenter.x;
  706.         theCenter->y = myPointer->fMovieCenter.y;
  707.     }        
  708. }
  709.  
  710.  
  711. //////////
  712. //
  713. // VRMoov_SetEmbeddedMovieCenter
  714. // Set the center of the embedded movie.
  715. //
  716. //////////
  717.  
  718. void VRMoov_SetEmbeddedMovieCenter (WindowObject theWindowObject, const QTVRFloatPoint *theCenter)
  719. {
  720.     QTVRInstance            myInstance;
  721.     float                    myX, myY;
  722.     VRScriptMoviePtr        myPointer;
  723.  
  724.     if (theWindowObject == NULL)
  725.         return;
  726.         
  727.     myInstance = (**theWindowObject).fInstance;
  728.     if (myInstance == NULL)
  729.         return;
  730.     
  731.     myX = theCenter->x;
  732.     myY = theCenter->y;
  733.     
  734.     // subject the values passed in to the current view constraints
  735.     QTVRWrapAndConstrain(myInstance, kQTVRPan, myX, &myX);
  736.     QTVRWrapAndConstrain(myInstance, kQTVRTilt, myY, &myY);
  737.             
  738.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  739.     if (myPointer != NULL) {
  740.         myPointer->fMovieCenter.x = myX;
  741.         myPointer->fMovieCenter.y = myY;
  742.     }
  743.     
  744.     // clear out the existing area of interest
  745.     QTVRRefreshBackBuffer(myInstance, 0);
  746.  
  747.     // reinstall the back buffer imaging procedure
  748.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  749. }
  750.  
  751.  
  752. //////////
  753. //
  754. // VRMoov_GetEmbeddedMovieScale
  755. // Get the scale of the embedded movie.
  756. //
  757. //////////
  758.  
  759. float VRMoov_GetEmbeddedMovieScale (WindowObject theWindowObject)
  760. {
  761.     float                    myScale;
  762.     VRScriptMoviePtr        myPointer;
  763.     
  764.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  765.     if (myPointer == NULL)
  766.         myScale = 0.0;
  767.     else
  768.         myScale = myPointer->fMovieScale;
  769.  
  770.     return(myScale);
  771. }
  772.  
  773.  
  774. //////////
  775. //
  776. // VRMoov_SetEmbeddedMovieScale
  777. // Set the scale factor of the embedded movie.
  778. //
  779. //////////
  780.  
  781. void VRMoov_SetEmbeddedMovieScale (WindowObject theWindowObject, float theScale)
  782. {
  783.     QTVRInstance            myInstance;
  784.     VRScriptMoviePtr        myPointer;
  785.  
  786.     if (theWindowObject == NULL)
  787.         return;
  788.         
  789.     myInstance = (**theWindowObject).fInstance;
  790.     if (myInstance == NULL)
  791.         return;
  792.     
  793.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  794.     if (myPointer != NULL)
  795.         myPointer->fMovieScale = theScale;
  796.     
  797.     // clear out the existing area of interest
  798.     QTVRRefreshBackBuffer(myInstance, 0);
  799.  
  800.     // reinstall the back buffer imaging procedure
  801.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  802. }
  803.  
  804.  
  805. //////////
  806. //
  807. // VRMoov_GetEmbeddedMovieRect
  808. // Get the rectangle of the embedded movie.
  809. //
  810. //////////
  811.  
  812. void VRMoov_GetEmbeddedMovieRect (WindowObject theWindowObject, Rect *theRect)
  813. {
  814.     VRScriptMoviePtr        myPointer;
  815.     
  816.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  817.     if (myPointer == NULL) {
  818.         theRect->left = 0.0;
  819.         theRect->top = 0.0;
  820.         theRect->right = 0.0;
  821.         theRect->bottom = 0.0;
  822.     } else {
  823.         theRect->left = myPointer->fMovieRect.left;
  824.         theRect->top = myPointer->fMovieRect.top;
  825.         theRect->right = myPointer->fMovieRect.right;
  826.         theRect->bottom = myPointer->fMovieRect.bottom;
  827.     }        
  828. }
  829.  
  830.  
  831. //////////
  832. //
  833. // VRMoov_SetEmbeddedMovieRect
  834. // Set the rectangle of the embedded movie.
  835. //
  836. //////////
  837.  
  838. void VRMoov_SetEmbeddedMovieRect (WindowObject theWindowObject, const Rect *theRect)
  839. {
  840.     QTVRInstance            myInstance;
  841.     VRScriptMoviePtr        myPointer;
  842.  
  843.     if (theWindowObject == NULL)
  844.         return;
  845.         
  846.     myInstance = (**theWindowObject).fInstance;
  847.     if (myInstance == NULL)
  848.         return;
  849.     
  850.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  851.     if (myPointer != NULL) {
  852.         myPointer->fMovieRect.right = theRect->right;
  853.         myPointer->fMovieRect.bottom = theRect->bottom;
  854.     }
  855.  
  856.     // clear out the existing area of interest
  857.     QTVRRefreshBackBuffer(myInstance, 0);
  858.  
  859.     // reinstall the back buffer imaging procedure
  860.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  861. }
  862.  
  863.  
  864. //////////
  865. //
  866. // VRMoov_SetAllBalanceAndVolume
  867. // Set the balance and volume attenuation of all embedded QuickTime movies making sound.
  868. //
  869. //////////
  870.  
  871. void VRMoov_SetAllBalanceAndVolume (WindowObject theWindowObject, float thePan, float theTilt)
  872. {
  873.     ApplicationDataHdl        myAppData;
  874.     VRScriptMoviePtr        myPointer;
  875.     VRScript3DObjPtr        my3DObjPtr;
  876.     
  877.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  878.     if (myAppData == NULL)
  879.         return;
  880.  
  881.     // walk our linked list of embedded QuickTime movies and set the balance and volume of any localized sounds
  882.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  883.     while (myPointer != NULL) {
  884.         if (myPointer->fQTMovieHasSound)
  885.             if (myPointer->fSoundIsLocalized)
  886.                 VRMoov_SetOneBalanceAndVolume(myPointer->fMovie, myPointer->fMediaHandler, thePan, theTilt, myPointer->fMovieCenter.x, myPointer->fVolAngle);
  887.         myPointer = myPointer->fNextEntry;
  888.     }
  889.     
  890.     // walk our linked list of 3D objects and set the balance and volume of any texture-mapped movies
  891.     my3DObjPtr = (VRScript3DObjPtr)(**myAppData).fListArray[kVREntry_QD3DObject];
  892.     while (my3DObjPtr != NULL) {
  893.         if (my3DObjPtr->fTexture != NULL)
  894.             if (my3DObjPtr->fTextureIsMovie)
  895.                 if ((**my3DObjPtr->fTexture).fMediaHandler != NULL)
  896.                     VRMoov_SetOneBalanceAndVolume((**my3DObjPtr->fTexture).fMovie, (**my3DObjPtr->fTexture).fMediaHandler, thePan, theTilt, QTVRUtils_Point3DToPanAngle(-1.0 * my3DObjPtr->fGroupCenter.x, my3DObjPtr->fGroupCenter.y, -1.0 * my3DObjPtr->fGroupCenter.z), QTVRUtils_DegreesToRadians(kVR_TextureMovieVolAngle));
  897.         my3DObjPtr = my3DObjPtr->fNextEntry;
  898.     }
  899.     
  900. }
  901.     
  902.     
  903. //////////
  904. //
  905. // VRMoov_SetOneBalanceAndVolume
  906. // Set the balance and volume attenuation of an embedded QuickTime movie.
  907. //
  908. //////////
  909.  
  910. void VRMoov_SetOneBalanceAndVolume (Movie theMovie, MediaHandler theMediaHandler, float thePan, float theTilt, float theMoviePan, float theVolAngle)
  911. {
  912. #pragma unused(theTilt)
  913.  
  914.     short            myValue;
  915.     float            myPanDelta;
  916.     float            myCosDelta;            // cosine of pan angle delta from movie center
  917.     float            myCosLimit;            // cosine of attenuation cone limit angle
  918.     
  919.     myPanDelta = thePan - theMoviePan;
  920.  
  921.     // ***set the balance
  922.     myValue = kQTMaxSoundVolume * sin(myPanDelta);
  923.     MediaSetSoundBalance(theMediaHandler, myValue);
  924.     
  925.     // ***set the volume
  926.     myCosDelta = cos(myPanDelta);
  927.     myCosLimit = cos(theVolAngle);
  928.  
  929.     if (myCosDelta >= myCosLimit)
  930.         // inside cone of attenuation, volume scales from 1.0 (at center) to 0.0 (at cone edge)
  931.         myValue = kQTMaxSoundVolume * ((myCosDelta - myCosLimit) / (1 - myCosLimit));
  932.     else
  933.         // outside cone of attenuation, volume is 0.0;
  934.         myValue = kNoVolume;
  935.     
  936.     if (myValue != GetMovieVolume(theMovie))
  937.         SetMovieVolume(theMovie, myValue);
  938. }
  939.  
  940.  
  941. //////////
  942. //
  943. // VRMoov_BackBufferImagingProc
  944. // The back buffer imaging procedure:
  945. //    * get a frame of movie and image it into the back buffer
  946. //    * also, do any additional compositing that might be desired
  947. // This function is called by VRScript_BackBufferImagingProc.
  948. //
  949. //////////
  950.  
  951. PASCAL_RTN OSErr VRMoov_BackBufferImagingProc (QTVRInstance theInstance, Rect *theRect, UInt16 theAreaIndex, UInt32 theFlagsIn, UInt32 *theFlagsOut, WindowObject theWindowObject)
  952. {
  953. #pragma unused(theAreaIndex)
  954.  
  955.     ApplicationDataHdl        myAppData;
  956.     Movie                    myMovie;
  957.     Boolean                    myIsDrawing = theFlagsIn & kQTVRBackBufferRectVisible;
  958.     VRScriptMoviePtr        myPointer;
  959.     
  960.     // assume we're not going to draw anything
  961.     *theFlagsOut = 0;
  962.     
  963.     if ((theInstance == NULL) || (theWindowObject == NULL)) 
  964.         return(paramErr);
  965.  
  966.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  967.     if (myAppData == NULL) 
  968.         return(paramErr);
  969.  
  970.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  971.  
  972.     // make sure we've got an active movie to play
  973.     if (myPointer == NULL)
  974.         return(paramErr);
  975.         
  976.     myMovie = myPointer->fMovie;
  977.     if ((myMovie != NULL) && (!IsMovieDone(myMovie))) {
  978.         // we have an embedded movie, so play it
  979.         
  980.         GWorldPtr            myGWorld, myMovGWorld;
  981.         GDHandle            myGDevice, myMovGDevice;
  982.         Rect                myRect;
  983.         
  984. #if ALLOW_REALTIME_ROTATION
  985.         // reset movie rotation matrix, if necessary
  986.         if (!(**myAppData).fDrewPrevBBProc && myIsDrawing)
  987.             if (GetMatrixType(&(**myAppData).fRotationMatrix) != identityMatrixType)
  988.                 SetMovieMatrix(myMovie, &(**myAppData).fRotationMatrix);
  989. #endif
  990.  
  991.         // get the current graphics world
  992.         // (on entry, the current graphics world is [usually] set to the back buffer)
  993.         GetGWorld(&myGWorld, &myGDevice);
  994.  
  995.         // get the embedded movie's graphics world
  996.         GetMovieGWorld(myMovie, &myMovGWorld, &myMovGDevice);
  997.  
  998.         // make sure that the movie GWorld is set correctly
  999.         // (note that we call SetMovieGWorld only if we have to, for performance reasons)
  1000.         if (myPointer->fUseMovieGWorld) {
  1001.             // we're using an offscreen graphics world, so set movie's GWorld to be that offscreen graphics world
  1002.             if (myMovGWorld != myPointer->fMovieGWorld)
  1003.                 SetMovieGWorld(myMovie, myPointer->fMovieGWorld, GetGWorldDevice(myPointer->fMovieGWorld));        
  1004.         } else {
  1005.             // we're not using an offscreen graphics world, so set movie GWorld to be the back buffer
  1006.             if ((myMovGWorld != myGWorld) || (myMovGDevice != myGDevice)) 
  1007.                 SetMovieGWorld(myMovie, myGWorld, myGDevice);
  1008.         }
  1009.         
  1010.         if (myIsDrawing) {
  1011.             // make sure the movie's rect matches our area of interest
  1012.             GetMovieBox(myMovie, &myRect);
  1013.             if (!MacEqualRect(&myRect, theRect))
  1014.                 SetMovieBox(myMovie, theRect);
  1015. #if ALLOW_REALTIME_ROTATION
  1016.             (**myAppData).fDrewPrevBBProc = true;
  1017. #endif
  1018.         } else {
  1019.             // if we're not visible, make sure we're not wasting time trying to draw
  1020.             MacSetRect(&myRect, 0, 0, 0, 0);
  1021.             SetMovieBox(myMovie, &myRect);
  1022. #if ALLOW_REALTIME_ROTATION
  1023.             (**myAppData).fDrewPrevBBProc = false;
  1024. #endif
  1025.         }
  1026.         
  1027.         // give the movie some time to play;
  1028.         // that is, draw a new frame into the movie's graphics world (and play movie sound)
  1029.         MoviesTask(myMovie, 0);
  1030.         
  1031.         // ***insertion (A) here***
  1032.         
  1033.         if (myIsDrawing) {
  1034.         
  1035.             // if we're visible, say we're drawing
  1036.             *theFlagsOut = kQTVRBackBufferFlagDidDraw;
  1037.             
  1038.             // now, if we're using an offscreen graphics world, copy it into the back buffer
  1039.             if (myPointer->fUseMovieGWorld) {
  1040.                 PixMapHandle    myPixMap;
  1041.                 
  1042.                 myPixMap = GetGWorldPixMap(myGWorld);
  1043.                 LockPixels(myPixMap);
  1044.                 
  1045.                 // set the chroma key color, if necessary
  1046.                 if (myPointer->fCompositeMovie) {
  1047.                     RGBBackColor(&(myPointer->fChromaColor));
  1048.                     OpColor(&myPointer->fChromaColor);
  1049.                 }
  1050.                 
  1051. #if USE_COPYBITS_TO_BACKBUFFER
  1052.                 // copy the current movie frame to the current graphics world
  1053.                 CopyBits(    (BitMap *)(*myPointer->fMoviePixMap),
  1054.                             (BitMap *)(*myPixMap),
  1055.                             &(*myPointer->fMovieGWorld).portRect, 
  1056.                             theRect,
  1057.                             srcCopy | transparent, 
  1058.                             NULL);
  1059. #else
  1060.                 {
  1061.                        ImageDescriptionHandle        myImageDesc;
  1062.                        PixMapHandle                myGWPixMap = NULL;
  1063.                        
  1064.                        myGWPixMap = GetGWorldPixMap(myPointer->fMovieGWorld);
  1065.  
  1066.                        SetGWorld(myGWorld, NULL);
  1067.                 
  1068.                        MakeImageDescriptionForPixMap(myGWPixMap, &myImageDesc);
  1069.                     DecompressImage(GetPixBaseAddr(myGWPixMap),
  1070.                                     myImageDesc,
  1071.                                        myPixMap,
  1072.                                        NULL,
  1073.                                        &myGWorld->portRect,
  1074.                                        srcCopy | transparent,
  1075.                                        NULL);
  1076.  
  1077.                        DisposeHandle((Handle)myImageDesc);
  1078.                }
  1079. #endif
  1080.                 // reset the chroma key color;
  1081.                 // we need to do this because the buffer we just drew into might NOT actually
  1082.                 // be the real back buffer (see Virtual Reality Programming With QuickTime VR, p. 1-154);
  1083.                 // the copy between the intermediate buffer and the back buffer respects the current back color.
  1084.                 if (myPointer->fCompositeMovie)
  1085.                     RGBBackColor(&kWhiteColor);
  1086.                     
  1087.                 UnlockPixels(myPixMap);
  1088.             }
  1089.         }
  1090.         
  1091.     } else {
  1092.         // we don't have an embedded movie, so remove this back buffer imaging procedure
  1093.         VRScript_RemoveBackBufferImagingProc((**theWindowObject).fInstance, theWindowObject);
  1094.     }
  1095.     
  1096.     return(noErr);
  1097. }
  1098.  
  1099.  
  1100. //////////
  1101. //
  1102. // VRMoov_CoverProc
  1103. // The cover function of the embedded movie.
  1104. //
  1105. //////////
  1106.  
  1107. PASCAL_RTN OSErr VRMoov_CoverProc (Movie theMovie, RgnHandle theRegion, WindowObject theWindowObject)
  1108. {
  1109. #pragma unused(theMovie, theRegion, theWindowObject)
  1110.  
  1111.     return(noErr);
  1112. }
  1113.  
  1114.  
  1115. //////////
  1116. //
  1117. // VRMoov_SetVideoGraphicsMode
  1118. // Set the video media graphics mode of the embedded movie.
  1119. //
  1120. //////////
  1121.  
  1122. void VRMoov_SetVideoGraphicsMode (Movie theMovie, VRScriptMoviePtr theEntry, Boolean theSetVGM)
  1123. {
  1124.     Track        myTrack;
  1125.     Media        myMedia;
  1126.  
  1127.     if (theEntry == NULL)
  1128.         return;
  1129.         
  1130.     myTrack = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  1131.     if (myTrack != NULL) {
  1132.         myMedia = GetTrackMedia(myTrack);
  1133.         if (theSetVGM)
  1134.             MediaSetGraphicsMode(GetMediaHandler(myMedia), srcCopy | transparent, &theEntry->fChromaColor);
  1135.         else
  1136.             MediaSetGraphicsMode(GetMediaHandler(myMedia), srcCopy, &kWhiteColor);
  1137.     } 
  1138.         
  1139.     return;
  1140. }
  1141.  
  1142.  
  1143. //////////
  1144. //
  1145. // VRMoov_GetFinishedMovie
  1146. // Get the first enlisted movie that is done playing.
  1147. //
  1148. //////////
  1149.  
  1150. VRScriptMoviePtr VRMoov_GetFinishedMovie (WindowObject theWindowObject)
  1151. {
  1152.     ApplicationDataHdl    myAppData;
  1153.     VRScriptMoviePtr    myPointer = NULL;
  1154.  
  1155.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);    
  1156.     if (myAppData == NULL)
  1157.         return(NULL);
  1158.     
  1159.     // walk our linked list of movies to find the target movie
  1160.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  1161.     while (myPointer != NULL) {
  1162.         if (IsMovieDone(myPointer->fMovie))
  1163.             return(myPointer);
  1164.         
  1165.         myPointer = myPointer->fNextEntry;
  1166.     }
  1167.     
  1168.     return(NULL);
  1169. }
  1170.  
  1171.  
  1172. //////////
  1173. //
  1174. // VRMoov_CheckForCompletedMovies
  1175. // Clean up any movies that are finished playing.
  1176. //
  1177. //////////
  1178.  
  1179. void VRMoov_CheckForCompletedMovies (WindowObject theWindowObject)
  1180. {
  1181.     VRScriptMoviePtr        myPointer = NULL;
  1182.     
  1183.     // delist any completed movies for the specified movie window
  1184.     if (theWindowObject != NULL)
  1185.         while ((myPointer = VRMoov_GetFinishedMovie(theWindowObject)) != NULL)
  1186.             VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  1187. }
  1188.  
  1189.  
  1190. //////////
  1191. //
  1192. // VRMoov_DumpEntryMem
  1193. // Release any memory associated with the specified list entry.
  1194. //
  1195. //////////
  1196.  
  1197. void VRMoov_DumpEntryMem (VRScriptMoviePtr theEntry)
  1198. {
  1199.     if (theEntry != NULL) {
  1200.         DisposeMovie(theEntry->fMovie);
  1201.         
  1202.         if (theEntry->fQTMovieHasVideo) {
  1203.             if (theEntry->fMoviePixMap != NULL)
  1204.                 UnlockPixels(theEntry->fMoviePixMap);
  1205.             if (theEntry->fMovieGWorld != NULL)
  1206.                 DisposeGWorld(theEntry->fMovieGWorld);
  1207.             if (theEntry->fHideRegion != NULL)
  1208.                 DisposeRgn(theEntry->fHideRegion);
  1209.         }
  1210.         
  1211.         free(theEntry->fPathname);
  1212.     }
  1213. }